package org.mercworks.igamexmlparser.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.mercworks.igamexmlparser.dvo.EulerController;
import org.mercworks.igamexmlparser.dvo.EulerX;
import org.mercworks.igamexmlparser.dvo.EulerY;
import org.mercworks.igamexmlparser.dvo.EulerZ;
import org.mercworks.igamexmlparser.dvo.FaceVertex;
import org.mercworks.igamexmlparser.dvo.Faces;
import org.mercworks.igamexmlparser.dvo.IGameBone;
import org.mercworks.igamexmlparser.dvo.IGameModel;
import org.mercworks.igamexmlparser.dvo.Key;
import org.mercworks.igamexmlparser.dvo.Mesh;
import org.mercworks.igamexmlparser.dvo.Modifier;
import org.mercworks.igamexmlparser.dvo.Modifiers;
import org.mercworks.igamexmlparser.dvo.Node;
import org.mercworks.igamexmlparser.dvo.IGameVertex;
import org.mercworks.igamexmlparser.dvo.PositionController;
import org.mercworks.igamexmlparser.dvo.PositionXYZController;
import org.mercworks.igamexmlparser.dvo.Skin;
import org.mercworks.knightgame.model.KnightGameModel;
import org.mercworks.knightgame.model.dvo.Animation;
import org.mercworks.knightgame.model.dvo.Bone;
import org.mercworks.knightgame.model.dvo.Face;
import org.mercworks.knightgame.model.dvo.KeyFrame;
import org.mercworks.knightgame.model.dvo.Vertex;

public abstract class IGameModelConverter
{
	public static KnightGameModel convertToKnightGameModel(IGameModel iGameModel)
	{
		KnightGameModel kgModel = new KnightGameModel();
		
		List<Node> listNodes = iGameModel.getListNodes();
		
		if(listNodes != null)
		{
			List<Animation> listAnimations = new ArrayList<Animation>();
			for(Node node : listNodes)
			{
				Mesh mesh = node.getMesh();
				Modifiers modifiers = node.getModifiers();
				EulerController eulerController = node.getEulerController();
				PositionXYZController positionController = node.getPositionXYZController();
				
				if(mesh != null)
				{
					Faces faces = mesh.getFaces();
					if(faces != null)
					{
						List<FaceVertex> listFaceVertex = faces.getListFaceVertex();
						
						if(listFaceVertex != null)
						{
							/* Create a new array list to hold the KnightGameModel faces */
							List<Face> listFaces = new ArrayList<Face>();
							
							/* Loop over the face objects and set the faces up for the KnightGameModel */
							for(FaceVertex faceVertex : listFaceVertex)
							{
								Face face = new Face();
								face.setFaceA(faceVertex.getFaceX().intValue());
								face.setFaceB(faceVertex.getFaceY().intValue());
								face.setFaceC(faceVertex.getFaceZ().intValue());
								
								listFaces.add(face);
							}
							
							/* This list can be cleared because it is no longer needed */
							listFaceVertex.clear();
							
							kgModel.setListFaces(listFaces);
						}
					}
					
					List<IGameVertex> listIGameVertex = mesh.getListVertex();
					
					if(listIGameVertex != null)
					{
						List<Vertex> listVertices = new ArrayList<Vertex>();
						
						for(IGameVertex iGameVertex : listIGameVertex)
						{
							Vertex vertex = new Vertex();
							vertex.setVertexId(iGameVertex.getVertexId().intValue());
							vertex.setX(iGameVertex.getX().intValue());
							vertex.setY(iGameVertex.getY().intValue());
							vertex.setZ(iGameVertex.getZ().intValue());
							listVertices.add(vertex);
						}
						
						/* This list can be cleared because it is no longer needed */
						listIGameVertex.clear();
						
						kgModel.setListVertices(listVertices);
					}
				} /* end if mesh is not null */
				
				if(modifiers != null)
				{
					List<Modifier> listModifiers = modifiers.getListModifiers();
					if(listModifiers != null)
					{
						for(Modifier modifier : listModifiers)
						{
							List<Skin> listSkins = modifier.getListSkins();
							
							if(listSkins != null)
							{
								Map<Integer, List<Bone>> mapListBones = kgModel.getMapListBones();
								
								if(mapListBones == null)
									mapListBones = new HashMap<Integer, List<Bone>>();
								
								for(Skin skin : listSkins)
								{
									int skinId = skin.getVertexId().intValue();
									
									List<IGameBone> listIGameBones = skin.getListIGameBones();
									
									if(listIGameBones != null)
									{
										for(IGameBone iGameBone : listIGameBones)
										{
											Bone bone = new Bone();
											bone.setBoneId(iGameBone.getBoneId().intValue());
											
											Double boneWeight = iGameBone.getWeight();
											
											bone.setBoneWeight(boneWeight == null ? 0.0 : boneWeight.doubleValue());
											bone.setSkinId(skinId);
											
											List<Bone> listBones = mapListBones.get(iGameBone.getBoneId());
											
											if(listBones == null)
											{
												listBones = new ArrayList<Bone>();
												listBones.add(bone);
												mapListBones.put(iGameBone.getBoneId(), listBones);
											}
											else
												listBones.add(bone);
										}
										
										listIGameBones.clear();
									}
								} /* end loop skins */
								
								kgModel.setMapListBones(mapListBones);
								
								listSkins.clear();
							} /* end skins not null */
						} /* end loop modifiers */
					} /* end modifiers not null */
				} /* end modifiers not null */
				
				Animation animation = new Animation();
				animation.setBoneId(node.getNodeId());
				
				if(positionController != null)
				{
					List<KeyFrame> listKeyFrames = null;
					
					PositionController positionControllerX = positionController.getPositionControllerX(); 
					PositionController positionControllerY = positionController.getPositionControllerY();
					PositionController positionControllerZ = positionController.getPositionControllerZ();
					
					if(positionControllerX != null)
					{
						List<Key> listKeys = positionControllerX.getListKeys();
						if(listKeys != null)
							listKeyFrames = getListKeyFrames(listKeys, false);
						
						if(!listKeyFrames.isEmpty())
							animation.setAnimationPosX(listKeyFrames);
					}
					
					if(positionControllerY != null)
					{
						List<Key> listKeys = positionControllerY.getListKeys();
						if(listKeys != null)
							listKeyFrames = getListKeyFrames(listKeys, false);
						
						if(!listKeyFrames.isEmpty())
							animation.setAnimationPosY(listKeyFrames);
					}
					
					if(positionControllerZ != null)
					{
						List<Key> listKeys = positionControllerZ.getListKeys();
						if(listKeys != null)
							listKeyFrames = getListKeyFrames(listKeys, false);
						
						if(!listKeyFrames.isEmpty())
							animation.setAnimationPosZ(listKeyFrames);
					}
				} /* end position controller not null */
				
				if(eulerController != null)
				{
					List<KeyFrame> listKeyFrames = null;
					
					EulerX eulerX = eulerController.getEulerX();
					EulerY eulerY = eulerController.getEulerY();
					EulerZ eulerZ = eulerController.getEulerZ();
					
					if(eulerX != null)
					{
						List<Key> listKeys = eulerX.getListKeys();
						if(listKeys != null)
							listKeyFrames = getListKeyFrames(listKeys, true);
						
						if(!listKeyFrames.isEmpty())
							animation.setAnimationRotX(listKeyFrames);
					}
					
					if(eulerY != null)
					{
						List<Key> listKeys = eulerY.getListKeys();
						if(listKeys != null)
							listKeyFrames = getListKeyFrames(listKeys, true);
						
						if(!listKeyFrames.isEmpty())
							animation.setAnimationRotY(listKeyFrames);
					}
					
					if(eulerZ != null)
					{
						List<Key> listKeys = eulerZ.getListKeys();
						if(listKeys != null)
							listKeyFrames = getListKeyFrames(listKeys, true);
						
						if(!listKeyFrames.isEmpty())
							animation.setAnimationRotZ(listKeyFrames);
					}
				}
				
				if(!animation.isEmpty())
					listAnimations.add(animation);
			} /* end loop nodes */
			
			kgModel.setListAnimations(listAnimations);
		} /* end nodes not null */
		
		return kgModel;
	}
	
	private static List<KeyFrame> getListKeyFrames(List<Key> listKeys, boolean isRotation)
	{
		List<KeyFrame> listKeyFrames = new ArrayList<KeyFrame>();
		final int FRAMES_PER_TIME = 4;
		
		for(int i = 0; i < listKeys.size() - 1; i++)
		{
			Key firstKey = listKeys.get(i);
			Key secondKey = listKeys.get(i + 1);
			
			int totalTime = secondKey.getTime().intValue() - firstKey.getTime().intValue();
			
			double tempValue = 0.0;
			
			if(isRotation)
				tempValue = Math.toDegrees(secondKey.getValue().doubleValue()) - Math.toDegrees(firstKey.getValue().doubleValue());
			else	
				tempValue = secondKey.getValue().floatValue() - firstKey.getValue().floatValue();
			
			float netValue = new Float(tempValue).floatValue();
			
			float step = netValue / ((totalTime / 1000) * FRAMES_PER_TIME);
			
			float convertedTime = totalTime / 1000.0f;
			
			KeyFrame keyFrame = new KeyFrame();
			keyFrame.setMaxFrame(Math.round(convertedTime));
			keyFrame.setStep(step);
			
			if(step != 0.0)
				listKeyFrames.add(keyFrame);
		}
		
		return listKeyFrames;
	}
}
